import base64
import hashlib
import hmac
import re
import time
import urllib

import requests


def content_url(func):
    def inner(self, text, *args, pc_slide=False, **kwargs):
        if pc_slide:
            result = re.findall('(?!\S*\.(?i:jpg|jpeg|png|gif))http[s]{0,1}://[\w\.\-/]+', text)  # 排除图片地址
            for ori_url in result:
                pc_slide_url = f'dingtalk://dingtalkclient/page/link?url={ori_url}&pc_slide=true'
                text = text.replace(ori_url, pc_slide_url)
        return func(self, text, *args, pc_slide=pc_slide, **kwargs)

    return inner


def link_url(func):
    def inner(self, messageUrl, *args, pc_slide=False, **kwargs):
        if pc_slide:
            messageUrl = f'dingtalk://dingtalkclient/page/link?url={messageUrl}&pc_slide=true'
        return func(self, *args, messageUrl=messageUrl, pc_slide=pc_slide, **kwargs)

    return inner


class WorkPlatform:
    def __init__(self, corpId, agentId):
        self.corpId = corpId
        self.agentId = agentId


class ActionCardButton:
    '''
    跳转卡片按钮类
    '''

    def __init__(self, title, actionURL, pc_slide=True):
        '''

        @param title:
        @param actionURL: 跳转链接
        @param pc_slide: True:PC客户端侧边栏打开  False:在浏览器打开
        @param work_platform: 工作台打开链接
        '''
        self.title = title
        self.actionURL = actionURL
        self.pc_slide = pc_slide

    @property
    def btn_dict(self):
        if not self.pc_slide:
            actionURL = f'dingtalk://dingtalkclient/page/link?url={self.actionURL}&pc_slide=false'
        else:
            actionURL = self.actionURL
        return {
            'title': self.title,
            'actionURL': actionURL,
        }


class FeedCardLink:
    '''
    FeedCard按钮类
    '''

    def __init__(self, title, messageURL, picURL, work_platform_obj: WorkPlatform = None):
        '''

        @param title:
        @param actionURL: 跳转链接
        小程序打开，请参考：https://open.dingtalk.com/document/orgapp-server/message-link-description
        要打开的链接，必须urlEncode
        '''
        self.title = title
        self.messageURL = messageURL
        self.picURL = picURL
        self.work_platform_obj = work_platform_obj

    @property
    def btn_dict(self):
        if self.work_platform_obj:
            messageURL = f'dingtalk://dingtalkclient/action/openapp?container_type=work_platform&corpid={self.work_platform_obj.corpId}&app_id=0_{self.work_platform_obj.agentId}&redirect_type=jump&redirect_url={self.messageURL}'
        else:
            messageURL = self.messageURL
        return {
            'title': self.title,
            'messageURL': messageURL,
            'picURL': self.picURL,
        }


class Robot:
    def __init__(self, secret='', access_token='', app_secret=''):
        self.secret = secret
        self.access_token = access_token
        self.app_secret = app_secret

    @classmethod
    def check_sign(cls, timestamp, app_secret):
        app_secret_enc = app_secret.encode('utf-8')
        string_to_sign = '{}\n{}'.format(timestamp, app_secret)
        string_to_sign_enc = string_to_sign.encode('utf-8')
        hmac_code = hmac.new(app_secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
        sign = base64.b64encode(hmac_code).decode('utf-8')

        return sign

    def get_timestamp_and_sign(self):
        secret = self.secret
        timestamp = str(round(time.time() * 1000))
        secret_enc = secret.encode('utf-8')
        string_to_sign = '{}\n{}'.format(timestamp, secret)
        string_to_sign_enc = string_to_sign.encode('utf-8')
        hmac_code = hmac.new(secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
        sign = urllib.parse.quote_plus(base64.b64encode(hmac_code))

        return timestamp, sign

    def send_massage(self, data, url=None):
        timestamp, sign = self.get_timestamp_and_sign()
        if not url:
            url = f'https://oapi.dingtalk.com/robot/send?access_token={self.access_token}&timestamp={timestamp}&sign={sign}'

        r = requests.post(url, json=data)
        response = r.text

        return response

    @content_url
    def send_md_msg(self,
                    text,
                    title='this is a title',
                    atByMobiles=[],
                    atByUserIds=[],
                    atAll=False,
                    pc_slide=False,
                    *args,
                    **kwargs
                    ):
        '''
        发送markdown文本
        @param text:
        @param title:
        @param atByMobiles:
        @param atByUserIds:
        @param atAll:
        @return:
        '''
        data = {
            "msgtype": "markdown",
            "markdown": {
                'text': text,
                'title': title,
            },
            "at": {
                "atMobiles": [atByMobiles],
                "atUserIds": [atByUserIds],
                "isAtAll": atAll
            }
        }
        res = self.send_massage(data, *args, **kwargs)
        return res

    @content_url
    def send_text_msg(self,
                      text,
                      atByMobiles=[],
                      atByUserIds=[],
                      atAll=False,
                      pc_slide=False,
                      *args,
                      **kwargs
                      ):
        '''
        发送纯文本信息
        @param text:
        @param atByMobiles:
        @param atByUserIds:
        @param atAll:
        @return:
        '''
        data = {
            "msgtype": "text",
            "text": {
                "content": text,
            },
            "at": {
                "atMobiles": [atByMobiles],
                "atUserIds": [atByUserIds],
                "isAtAll": atAll
            }
        }
        res = self.send_massage(data, *args, **kwargs)
        return res

    @link_url
    def send_link_msg(self,
                      text,
                      messageUrl,
                      title='this is a title',
                      picUrl=None,
                      pc_slide=False,
                      *args,
                      **kwargs
                      ):
        '''
        发送链接（卡片）信息，不支持@
        @param text:
        @param messageUrl:
        @param title:
        @param picUrl:
        @return:
        '''
        data = {
            "msgtype": "link",
            "link": {
                "text": text,
                "title": title,
                "picUrl": picUrl,
                "messageUrl": messageUrl
            },
        }
        res = self.send_massage(data, *args, **kwargs)
        return res

    def send_actionCard_msg(self,
                            text,
                            btns: [list],
                            title='this is a title',
                            btnColumn=True,
                            *args,
                            **kwargs
                            ):
        '''
        发送按钮跳转信息，不支持@
        @param text:markdown格式的消息
        @param btns:ActionCardButton Object
        @param title:
        @param btnColumn:按钮是否纵向
        @return:
        '''
        btnOrientation = 0 if btnColumn else 1
        data = {
            "msgtype": "actionCard",
            "actionCard": {
                "title": title,
                "text": text,
                "btnOrientation": btnOrientation,
                "btns": [btn.btn_dict for btn in btns],
            },
        }
        res = self.send_massage(data, *args, **kwargs)
        return res

    def send_feedCard_msg(self, btns: [list], *args, **kwargs):
        '''
        发送微信公众号风多条卡片信息，不支持@
        @param btns:FeedCardLink Object
        @return:
        '''
        data = {
            "msgtype": "feedCard",
            "feedCard": {
                "links": [btn.btn_dict for btn in btns]
            },
        }
        res = self.send_massage(data, *args, **kwargs)
        return res
